<?php

namespace Framework\Foundation\Zipkin;

use Framework\Foundation\Request\ServerRequestProxy;
use Zipkin\Endpoint;
use Zipkin\Reporter;
use Zipkin\Samplers\BinarySampler;
use Zipkin\Reporters\Http;
use Zipkin\Span;
use Zipkin\Tracer;
use Zipkin\TracingBuilder;
use Zipkin\DefaultTracing;

class ZipkinAssistant
{
    /**
     * @var DefaultTracing;
     */
    protected $tracing;

    /**
     * @var Tracer;
     */
    public $tracer;

    /**
     * @var Span;
     */
    protected $tempCurrentSpan;

    public function __construct(Reporter $reporter, $serviceName = 'default', $config = [])
    {
        if (isset($config['tracing']['ip4'])) {
            $ip4 = $config['tracing']['ip4'];
        } else {
            $ip4 = array_key_exists('REMOTE_ADDR', $_SERVER) ? $_SERVER['REMOTE_ADDR'] : null;
        }

        if (isset($config['tracing']['ip6'])) {
            $ip6 = $config['tracing']['ip6'];
        } else {
            $ip6 = null;
        }

        if (isset($config['tracing']['port'])) {
            $port = $config['tracing']['port'];
        } else {
            $port = array_key_exists('REMOTE_PORT', $_SERVER) ? (int)$_SERVER['REMOTE_PORT'] : null;
        }

        $endpoint = Endpoint::create($serviceName, $ip4, $ip6, $port);
        $sampler = BinarySampler::createAsAlwaysSample();

        $this->tracing = TracingBuilder::create()
            ->havingLocalEndpoint($endpoint)
            ->havingSampler($sampler)
            ->havingReporter($reporter)
            ->build();

        $this->tracer = $this->tracing->getTracer();
    }

    public function autoGetSpan()
    {
        // 实例中tempCurrentSpan不为null代表是应用内连续获取span
        if (!is_null($this->tempCurrentSpan)) {
            $this->tempCurrentSpan = $this->tracer->nextSpan($this->tempCurrentSpan->getContext());
            return $this->tempCurrentSpan;
        }

        // 从header获得传播span
        $propagationContext = $this->propagationContext();
        if ($propagationContext instanceof \Zipkin\Propagation\TraceContext) {
            $this->tempCurrentSpan = $this->tracer->nextSpan($propagationContext);
            return $this->tempCurrentSpan;
        }

        // 生成一个根span返回
        $this->tempCurrentSpan = $this->rootSpan();
        return $this->tempCurrentSpan;
    }

    public function getNewSpan(Span $span = null)
    {
        $parentSpan = $span ?? $this->tracer->getCurrentSpan();
        return $this->tracer->nextSpan($parentSpan);
    }

    public function propagationContext()
    {
        $extractor = $this->tracing->getPropagation()->getExtractor(new ZipkinHttpHeadGetter());
        $extractedContext = $extractor(ServerRequestProxy::fromGlobalsAndHandleJson()->getServerRequest());
        return $extractedContext;
    }

    public function rootSpan()
    {
        return $this->tracer->newTrace();
    }

    public function getTracing()
    {
        return $this->tracing;
    }

    public function getTracer()
    {
        return $this->tracer;
    }
}
